﻿using System;
using System.Collections.Generic;
using System.Text;

namespace WorkNodeFramework
{
    public enum JoinType { 
        InnerJoin,
        LeffOuterJoin,
        RightOuterJoin,
        FullOuterJoin,
        CrossJoin
    }

    public interface IJoinClause 
    {
        ITable Table { get; }
        JoinType JoinType { get; }
    }

    public abstract class AbstractJoinClause : IJoinClause
    {
        ITable table;
        Column fromTableColumn;
        Column joinTableColumn;

        protected AbstractJoinClause(ITable table) {
            this.table = table;
        }

        public ITable Table
        {
            get
            {
                return table;
            }
        }

        public Column FromTableColumn
        {
            get
            {
                return fromTableColumn;
            }
            protected set {
                fromTableColumn = value;
            }
        }

        public Column JoinTableColumn
        {
            get
            {
                return joinTableColumn;
            }
            protected set {
                joinTableColumn = value;
            }
        }

        public abstract JoinType JoinType { get; }
    }

    public abstract class AbstractJoinClause<T>: AbstractJoinClause
        where T:Query<T>
    {
        Query<T> query;
        

        protected AbstractJoinClause(Query<T> query, ITable table)
            :base(table)
        {
            this.query = query;
        }

        protected Query<T> Query {
            get {
                return query;
            }
        }

        public T On(Column fromTableColumn, Column joinTableColumn)
        {
            base.FromTableColumn = fromTableColumn;
            base.JoinTableColumn = joinTableColumn;
            return (T)query;
        }
    }

    public class InnerJoin<T>: AbstractJoinClause<T>
        where T:Query<T>
    {
        public InnerJoin(Query<T> query, ITable table) 
            :base(query,table)
        {
        }

        public override JoinType JoinType
        {
            get { return JoinType.InnerJoin; }
        }
    }

    public class LeftOuterJoin<T> : AbstractJoinClause<T>
        where T:Query<T>
    {
        public LeftOuterJoin(Query<T> query, ITable table)
            :base(query,table)
        { 
        }

        public override JoinType JoinType
        {
            get { return JoinType.LeffOuterJoin; }
        }
    }

    public class RightOuterJoin<T> : AbstractJoinClause<T>
        where T : Query<T>
    {
        public RightOuterJoin(Query<T> query, ITable table)
            : base(query, table)
        {
        }

        public override JoinType JoinType
        {
            get { return JoinType.RightOuterJoin; }
        }
    }

    public class FullOuterJoin<T> : AbstractJoinClause<T>
        where T : Query<T>
    {
        public FullOuterJoin(Query<T> query, ITable table)
            : base(query, table)
        {
        }

        public override JoinType JoinType
        {
            get { return JoinType.FullOuterJoin; }
        }
    }

    public class CrossJoin : IJoinClause
    {
        ITable table;

        public CrossJoin(ITable table)
        {
            this.table = table;
        }
        #region IJoinClause Members

        public ITable Table
        {
            get { return table; }
        }

        public JoinType JoinType
        {
            get { return JoinType.CrossJoin; }
        }

        #endregion
    }

}
